the meaning of the instruction - python

I found this code in sqlmap project https://github.com/sqlmapproject/sqlmap/blob/master/lib/core/datatype.py
.
I don't understand the meaning of calling the constructor AttribDict.__init__(self)
class InjectionDict(AttribDict):
def __init__(self):
AttribDict.__init__(self)
self.place = None
self.parameter = None
self.ptype = None
self.prefix = None
self.suffix = None
self.clause = None
# data is a dict with various stype, each which is a dict with
# all the information specific for that stype
self.data = AttribDict()
# conf is a dict which stores current snapshot of important
# options used during detection
self.conf = AttribDict()
self.dbms = None
self.dbms_version = None
self.os = None

The InjectionDict class is a subclass, the base class it inherets from is AttribDict. That's what this syntax means
class InjectionDict(AttribDict):
Then in InjectDict's __init__ method, they are calling the base class's __init__ method first, before doing the rest of the subclass specific __init__ work.
AttribDict.__init__(self)
See this post for a more thorough explanation of what this behavior is used for.

Related

How to reference function defined in __init__ super class

I have a helper function (def convert(dictionary) inside my __init__ class to assist with configuration setup. The definition is as follows:
class Configuration:
def __init__(self, config_file=None, config=None):
if config_file is not None:
with open(config_file) as in_file:
self._config = yaml.load(in_file, Loader=yaml.FullLoader)
elif config is not None:
self._config = config
else:
raise ValueError("Could not create configuration. Must pass either location of config file or valid "
"config.")
def convert(dictionary):
return namedtuple('Config', dictionary.keys())(**dictionary)
This allows me to make a call within __init__ as follows:
self.input = convert(self._config["input"])
self.output = convert(self._config["output"])
self.build = convert(self._config["build_catalog"])
Since I have more than one configs to set up I want to inherit from his class as follows:
class BuildConfiguration(Configuration):
def __init__(self, config_file=None, config=None):
super().__init__(config_file, config)
self.input = convert(self._config["input"])
self.output = convert(self._config["output"])
self.build = convert(self._config["build_catalog"])
I however do not gain access to convert from the parent class. I have also tried this:
self.input = super().__init__.convert(self._config["input"])
This also seems to not work.
So the question is how do I get access to a function defined in super().__init__ from child classes?
You can't. A new function is created on each invocation of __init__ and it is discarded, it doesn't exist outside the function. Note, this also applies to the class being created by namedtuple('Config', dictionary.keys())(**dictionary). It really isn't good to keep creating all these unnecessary classes, which totally defeats the purpose of namedtuple which is for creating memory-efficient record-types. Here, each instance has it's own class!
Here is how you should define this:
Config = namedtuple('Config', "foo bar baz")
def convert(dictionary): # is this really necessary?
return Config(**dictionary)
class Configuration:
def __init__(self, config_file=None, config=None):
if config_file is not None:
with open(config_file) as in_file:
self._config = yaml.load(in_file, Loader=yaml.FullLoader)
elif config is not None:
self._config = config
else:
raise ValueError("Could not create configuration. Must pass either location of config file or valid "
"config.")
self.input = convert(self._config["input"])
self.output = convert(self._config["output"])
self.build = convert(self._config["build_catalog"])
Although at this point, it seems cleaner to just use
Config(**self._config["input"])
etc instead and ditch the helper convert.

Is Type[type] the correct type hint for a class object?

My question: is my usage of AnyType (as I have defined it below) correct? The goal is for AnyType to accept any class object, but instances of class objects, or function types, or other things that aren't of type type, should be rejected.
Details:
I have a class that looks something like this:
MixinSubclsType = Type["ChildRegistryMixin"]
AnyType = Type[type] # <- is this correct?
class ChildRegistryMixin:
"""Mixin class that creates classes which track subclasses.
Each new child class will track its own children."""
_subclasses: Dict[Any, MixinSubclsType] = dict()
_make_reg_key: Callable[[AnyType], Any]] = lambda subcls: getattr(subcls, "__name__")
def __init_subclass__(subcls,
make_reg_key: Optional[Callable[[AnyType], Any]]] = None,
**kwargs) -> None:
# implementation here
Is Type[type] the correct way to tell the type checker the lambda is supposed to only accept class objects?
Since more information is sometimes better than less, below is the entire implementation.
class ChildRegistryMixin:
"""Mixin class that creates classes which track subclasses.
Each new child class will track its own children.
Usage example 1:
class RegisteredByName(ChildRegistryMixin): ...
assert ChildRegistryMixin._subclasses["RegisteredByName"] is RegisteredByName
Usage example 2:
valid_lookup = dict(ClassName="othername")
class RegisteredByPop(ChildRegistryMixin,
make_reg_key=lambda subcls:
valid_lookup.pop(subcls.__name__)):
pass
class ClassName(RegisteredByPop): ...
assert RegisteredByPop._subclasses["othername"] is ClassName
class InvalidName(RegisteredByPop): ... # <-- ERROR!
"""
_subclasses: Dict[Any, MixinSubclsType] = dict()
_make_reg_key: Callable([AnyType], Any) = lambda subcls: getattr(subcls, "__name__")
def __init_subclass__(subcls,
make_reg_key: Optional[Callable([AnyType], Any)] = None,
**kwargs) -> None:
super().__init_subclass__(**kwargs)
# for later child classes of the new class
subcls._subclasses = dict()
# child added to the reg of closest parent that is a subclass of CRB
for parent_cls in subcls.mro()[1:]:
if issubclass(parent_cls, ChildRegistryMixin):
break
else:
parent_cls = ChildRegistryMixin
# make the key
key = parent_cls._make_reg_key(subcls)
# can't have multiple child classes with same key
if key not in parent_cls._subclasses:
parent_cls._subclasses[key] = subcls
else:
raise ChildRegistryError(f"Attempted to overwrite the "
f"child class key {key!r} in the "
f"{parent_cls.__name__} registry")
# inherit the subclass' key maker from parent if one was not provided
subcls._make_reg_key = parent_cls._make_reg_key if make_reg_key is None\
else make_reg_key

Passing a class as argument to a function and use it's methods

Quite simple, I wanna pass a class to a function as argument, while the class that I'm using has several methods. Here's the class: (parent is also a Node)
class Node:
def __init__(self,parent,foods):
self.state = state
self.foods = foods
self.parent = parent
def getParent(self):
return self.parent
def getFoods(self):
return self.foods
And somewhere else in a function I'm passing this class to function, but seems that I can't use all attributes. Here's the function:
def CalculateSomethingAboutThisNode(node):
daddy = node.getParent()
foodsOfDaddy = daddy.getFoods()
But I'm getting this error:
line 551, in CalculateSomethingAboutThisNode
foodsOfDaddy = daddy.getFoods()
AttributeError: 'NoneType' object has no attribute 'getFoods'
Please hep me out here.
The node has no parent. In other words: it's a root node.
As such it can happen that daddy is None and that means daddy.getFoods() won't work.
you should correct your code:
def CalculateSomethingAboutThisNode(node):
if not node is None:
daddy = node.getParent()
foodsOfDaddy = daddy.getFoods()

Creating an instance of type(self) dynamically without calling __init__?

This is quite hard to explain. I have a class which should support the method copy_stateonly(). It should return a crippled version of the object which only contains the (copied) data members that I want. I hope this example explains it better:
# everything inherits from this
class SuperBase:
def __init__(self):
self.state_var = 3 # this should be copied into future objects
self.non_state_var = 0 # we don't want to copy this
def copy_stateonly(self):
newobj = # ??????????? create instance without calling __init__
newobj.state_var = self.state_var
return newobj
# some clases inherit from this
class Base(SuperBase):
def __init__(self):
SuperBase.__init__(self)
self.isflying = True # we want to copy this, this is state
self.sprite = "sprites/plane_generic.png" # we must drop this
def copy_stateonly(self):
newobj = SuperBase.copy_stateonly(self)
newobj.isflying = self.isflying
return newobj
class A144fighter(Base):
def __init__(self, teamname): # note required __init__ argument
Base.__init__(self)
self.colors = ["black", "grey"] # we want to copy this, this is state
self.name = teamname # we must drop this
def copy_stateonly(self):
newobj = Base.copy_stateonly(self)
newobj.colors = self.colors[:]
return newobj
plane = A144fighter("team_blue")
plane_state = plane.copy_stateonly() # this should return an A144fighter object with only state_var, flying and colors set.
Python 2.7
I'm not aware of a way to create new instances of classic classes (which is what you used in your example) without calling __init__(). New instances of new-style classes (descendants of object) can be created using
object.__new__(cls)
where cls is the type of object you would like to create.
An alternative is to use copy.copy() for copying, possibly overwriting __getstate__() and __setstate__() to define what should be copied.
Edit: To create a new instance of a classic class cls without calling __init__(), you can use the following hack:
class EmptyClass:
pass
new_instance = EmptyClass()
new_instance.__class__ = cls
new_instance.__dict__.update(whatever)
Remember that every object has a attribute named __class__. If you do <object>.__class__ it, will return that object's class object (if that makes sense). The class object is callable so you can add parentheses to the end to create a new instance of that class.
newobj = self.__class__()
# everything inherits from this
class SuperBase:
def __init__(self):
self.state_var = 3 # this should be copied into future objects
self.non_state_var = 0 # we don't want to copy this
def __getstate__(self):
return { 'state_var' : self.state_var }
def __str__(self):
return self.__class__.__name__ + '(' + str(vars(self)) + ')'
# some clases inherit from this
class Base(SuperBase):
def __init__(self):
SuperBase.__init__(self)
self.isflying = True # we want to copy this, this is state
self.sprite = "sprites/plane_generic.png" # we must drop this
def __getstate__(self):
state = SuperBase.__getstate__(self)
state['isflying'] = self.isflying
return state
class A144fighter(Base):
def __init__(self, teamname): # note required __init__ argument
Base.__init__(self)
self.colors = ["black", "grey"] # we want to copy this, this is state
self.name = teamname # we must drop this
def __getstate__(self):
state = Base.__getstate__(self)
state['colors'] = self.colors[:]
return state
plane = A144fighter("team_blue")
print plane
import copy
print copy.copy(plane)
# or manually:
import types
print types.InstanceType(plane.__class__, plane.__getstate__())

Defining constants in python class, is self really needed?

I want to define a set of constants in a class like:
class Foo(object):
(NONEXISTING,VAGUE,CONFIRMED) = (0,1,2)
def __init__(self):
self.status = VAGUE
However, I get
NameError: global name 'VAGUE' is not defined
Is there a way of defining these constants to be visiable inside the class without resorting to global or self.NONEXISTING = 0 etc.?
When you assign to names in the class body, you're creating attributes of the class. You can't refer to them without referring to the class either directly or indirectly. You can use Foo.VAGUE as the other answers say, or you can use self.VAGUE. You do not have to assign to attributes of self.
Usually, using self.VAGUE is what you want because it allows subclasses to redefine the attribute without having to reimplement all the methods that use them -- not that that seems like a sensible thing to do in this particular example, but who knows.
try instead of:
self.status = VAGUE
this one:
self.status = Foo.VAGUE
you MUST specify the class
This one is NOT RECOMMENDED FOR ANY CODE by any means, but an ugly hack like below can be done.
I did this just to have better understanding of Python AST API, so anyone who uses this in real-world code should be shot before it does any harm :-)
#!/usr/bin/python
# -*- coding: utf-8-unix -*-
#
# AST hack to replace symbol reference in instance methods,
# so it will be resolved as a reference to class variables.
#
import inspect, types, ast
def trim(src):
lines = src.split("\n")
start = lines[0].lstrip()
n = lines[0].index(start)
src = "\n".join([line[n:] for line in lines])
return src
#
# Method decorator that replaces symbol reference in a method
# so it will use symbols in belonging class instead of the one
# in global namespace.
#
def nsinclude(*args):
# usecase: #nsinclude()
# use classname in calling frame as a fallback
stack = inspect.stack()
opts = [stack[1][3]]
def wrap(func):
if func.func_name == "tempfunc":
return func
def invoke(*args, **kw):
base = eval(opts[0])
src = trim(inspect.getsource(func))
basenode = ast.parse(src)
class hackfunc(ast.NodeTransformer):
def visit_Name(self, node):
try:
# if base class (set in #nsinclude) can resolve
# given name, modify AST node to use that instead
val = getattr(base, node.id)
newnode = ast.parse("%s.%s" % (opts[0], node.id))
newnode = next(ast.iter_child_nodes(newnode))
newnode = next(ast.iter_child_nodes(newnode))
ast.copy_location(newnode, node)
return ast.fix_missing_locations(newnode)
except:
return node
class hackcode(ast.NodeVisitor):
def visit_FunctionDef(self, node):
if func.func_name != "tempfunc":
node.name = "tempfunc"
hackfunc().visit(node)
hackcode().visit(basenode)
newmod = compile(basenode, '<ast>', 'exec')
eval(newmod)
newfunc = eval("tempfunc")
newfunc(*args, **kw)
return invoke
# usecase: #nsinclude
if args and isinstance(args[0], types.FunctionType):
return wrap(args[0])
# usecase: #nsinclude("someclass")
if args and args[0]:
opts[0] = args[0]
return wrap
class Bar:
FOO = 987
BAR = 876
class Foo:
FOO = 123
BAR = 234
# import from belonging class
#nsinclude
def dump1(self, *args):
print("dump1: FOO = " + str(FOO))
# import from specified class (Bar)
#nsinclude("Bar")
def dump2(self, *args):
print("dump2: BAR = " + str(BAR))
Foo().dump1()
Foo().dump2()
The only way is to access it through the class name such as
Foo.VAGUE
If accessing just VAGUE inside the __init__ function, or a function, it must be declared inside that to access it the way you want.
Using self is for the instance of the class also.
In Python3, you can also reference VAGUE as:
type(self).VAGUE
This way, you are clearly referencing it as a class attribute and not an object attribute, yet this way is robust against a name change of the class. Also if you override VAGUE in a subclass, the value from the subclass will be used, just like if you were to use self.VAGUE.
Note that this method does not appear to work in Python2, at least not in my tests, where type(self) returned instance instead of the class I instantiated. Therefore Thomas Wouters's answer is probably preferable, considering how widespread Python2 still is.

Categories

Resources