I have this:
def required(props):
props.fget.required = True
return props
class SomeClass():
#required
#property
def func(self):
return self.conname("conname")
But I want this: when self.name attribute of SomeClass equale "value" , then make the property optional, when non-equal leave required.
You could handle this in the initializer like so:
class SomeClass(object): # inherit from object if you are using python 2.7
def __init__(self, name, optional_required_property=None):
self.name = name
if name == "value" and optional_required_property is None:
raise AttributeError("optional_required_property cannot be None.")
else:
self.optional_required_property = optional_required_property
test_someclass = SomeClass("test") # will work
test_someclass = SomeClass("value") # will fail
Inspired by Stack Overflow Question: How to implement a required property in Python
Related
Say I have 2 different implementations of a class
class ParentA:
def initialize(self):
pass
def some_event(self):
pass
def order(self, value):
# handle order in some way for Parent A
class ParentB:
def initialize(self):
pass
def some_event(self):
pass
def order(self, value):
# handle order in another for Parent B
How can I dynamically let some 3rd class inherit from either ParentA or ParentB based on something like this?
class MyCode:
def initialize(self):
self.initial_value = 1
def some_event(self):
# handle event
order(self.initial_value)
# let MyCode inherit from ParentA and run
run(my_code, ParentA)
Simply store the class-object in a variable (in the example below, it is named base), and use the variable in the base-class-spec of your class statement.
def get_my_code(base):
class MyCode(base):
def initialize(self):
...
return MyCode
my_code = get_my_code(ParentA)
Also, you can use type builtin. As callable, it takes arguments: name, bases, dct (in its simplest form).
def initialize(self):
self.initial_value = 1
def some_event(self):
# handle event
order(self.initial_value)
subclass_body_dict = {
"initialize": initialize,
"some_event": some_event
}
base_class = ParentA # or ParentB, as you wish
MyCode = type("MyCode", (base_class, ), subclass_body_dict)
This is more explicit than snx2 solution, but still - I like his way better.
PS. of course, you dont have to store base_class, nor subclass_body_dict, you can build those values in type() call like:
MyCode = type("MyCode", (ParentA, ), {
"initialize": initialize,
"some_event": some_event
})
Just as a quick copy-and-paste-ready snippet, I've added the comments from shx2's answer to create this (memoized with a created_classes dict attribute, so that the classes created by successive identical calls with the same class will give identical classes):
class ParentA:
val = "ParentA"
class ParentB:
val = "ParentB"
class DynamicClassCreator():
def __init__(self):
self.created_classes = {}
def __call__(self, *bases):
rep = ",".join([i.__name__ for i in bases])
if rep in self.created_classes:
return self.created_classes[rep]
class MyCode(*bases):
pass
self.created_classes[rep] = MyCode
return MyCode
creator = DynamicClassCreator()
instance1 = creator(ParentA, ParentB)()
print(instance1.val) #prints "ParentA"
instance2 = creator(ParentB, ParentA)()
print(instance2.val) #prints "ParentB"
If you wanted to get fancy you could even make DynamicClassCreator a Singleton: https://stackoverflow.com/a/7346105/5122790
As an alternative to Chris's answer implementing the memoisation suggestion for shx2's answer, I'd prefer to use a memoize decorator (the end result is still a class but it's clearer to me that the function is the interface), and also use setdefault to simplify adding to the memo dict, and do not convert the names to string but use the tuple bases itself as the key, simplifying the code to:
class Memoize:
def __init__(self, f):
self.f = f
self.memo = {}
def __call__(self, *args):
return self.memo.setdefault(args, self.f(*args))
class ParentA:
def initialize(self):
pass
class ParentB:
def initialize(self):
pass
#Memoize
def get_my_code(base):
class MyCode(base):
def initialize(self):
pass
return MyCode
a1 = get_my_code(ParentA)
a2 = get_my_code(ParentA)
b1 = get_my_code(ParentB)
print(a1 is a2) # True
print(a1 is b1) # False
(Not a good example as the code provided doesn't actually do anything other than overwrite the parent class's initialize method...)
I need to get class name from class:
class Cls:
notation = None
def __init__(self):
notation = self.__class__.__name__
print(Cls.notation) prints None but I need 'Cls'
How to fix it or how to define class attribute which returns a name of class?
You are assigning to a local variable, not the class attribute:
def __init__(self):
Cls.notation = self.__class__.__name__
Note that self.__class__ isn't necessarily Cls, if there is a subclass of Cls involved. You might want to use
def __init__(self):
type(self).notation = self.__class__.__name__
depending on your use case.
Assigning to self.notation won't work, because that creates an instance attribute that shadows the class attribute.
If you want Cls.notation == "Cls" immediately after the class is defined, you may as well just hard-code it:
class Cls:
notation = "Cls"
or
class Cls:
pass
Cls.notation = Cls.__name__
though you can also write
class Cls:
notation = __qualname__
to set its value based on the name used in the first line of the statement, though __qualname__ takes into account nesting as well:
class Cls1:
class Cls2:
notation = __qualname__ # "Cls1.Cls2", not "Cls2"
This is a sample python object that I am working with.
class DataObj(object):
def __init__(self, cvid, cvname, address, get_info):
self.cvid = cvid
self.cvname = cvname
self.address = address
self.prof = PROF("Honda", "Jason Jones")
class PROF(object):
def __init__(self, organization, manager_name):
self.organization = organization
self.manager_name = manager_name
self.project_list = [Proj("asd", "asd"), Proj("asdsd", "asdsd")]
class Proj(object):
def __init__(self, projectname, projecttype):
self.projectname = projectname
self.projecttype = projecttype
I need to write a function that takes a list of fields and extract all the fields as key value pair from the DataObj. The trick is it should also look for attributes of object composed inside DataObj class. for example if list of fields is ["cvid", "organization", "projectname"], it should return something like this in the following format
{'cvid' : 'value', 'organization' : 'Honda', Proj :[{'projectname' : 'asd'}, {'projectname' : 'asdsd'}]
Where should I write this function, so my code is more modular? I was thinking about writing it inside DataObj but I wouldn't know what are the attributes of object composed inside DataObj. How to achieve what I am trying to do in more object oriented way?
All I did was simply add __iter__ which basically says hey, you can iterate over me, if you cast the object to an iterabale container type.
class Proj(object):
def __init__(self, projectname, projecttype):
self.projectname = projectname
self.projecttype = projecttype
def __iter__(self):
yield ("projectname", self.projectname)
class PROF(object):
def __init__(self, organization, manager_name):
self.organization = organization
self.manager_name = manager_name
self.project_list = [Proj("asd", "asd"), Proj("asdsd", "asdsd")]
def __iter__(self):
for proj in self.project_list:
yield (dict(proj))
class DataObj(object):
def __init__(self, cvid, cvname, address):
self.cvid = cvid
self.cvname = cvname
self.address = address
self.prof = PROF("Honda", "Jason Jones")
def __iter__(self):
yield ('cvid', self.cvid)
yield ('organization', self.prof.organization)
yield ("Proj", list(self.prof))
do = DataObj("1", "heinst", "A Street, Somewhere, USA")
print dict(do)
Between __getattr__ and operator.attrgetter, you could make this work fairly easily:
class DataObj(object):
def __init__(self, cvid, cvname, address, get_info):
self.cvid = cvid
self.cvname = cvname
self.address = address
self.prof = PROF("Honda", "Jason Jones")
def __getattr__(self, name):
# Called when an attribute is accessed which is not found on DataObj
# You can limit the loop to avoid checking some attributes, or
# remove the loop if only self.prof should be checked
for member in (self.cvid, self.cvname, self.address, self.prof):
try:
return getattr(member, name)
except AttributeError:
pass
raise AttributeError(name)
# If only self.prof should be checked, the function could simplify to:
# return getattr(self.prof, name)
Then you can make a simple utility function that runs against a DataObj to get an arbitrary set of key value pairs from it:
from operator import attrgetter
def extractdata(dataobj, *names):
return dict(zip(names, attrgetter(*names)(dataobj)))
Or as a member of DataObj, just name the first param self to match convention:
def extractdata(self, *names):
return dict(zip(names, attrgetter(*names)(self)))
__getattr__ allows delegation of attribute lookup to contained objects, and attrgetter allows you to retrieve a set of arbitrary attributes in a simple way.
Currently __setattr__ only works for instance. Is there any similar method for class? I am asking this question because I want to collect the list of defined attribute in order when user define it in class as below:
class CfgObj(object):
_fields = []
def __setattr__(self, name, value):
self._fields.append([name, value])
object.__setattr__(self, name, value)
class ACfg(CfgObj):
setting1 = Field(str, default='set1', desc='setting1 ...')
setting2 = Field(int, default=5, desc='setting2...')
I know the above code will not work as expected because the __setattr__ only called by instance as below:
acfg = ACfg()
acfg.c = 1
acfg._fields == [['c', 1]]
So, is there any equivalent __setattr__ for python class? The main purpose is to collect the define attribute in order when user define it in class.
Yes, but that's not how you want to do it.
class MC(type):
def __init__(cls, name, bases, dct):
print dct
super(MC, cls).__init__(name, bases, dct)
class C(object):
__metaclass__ = MC
foo = 42
If you define __setattr__() on the metaclass of a class, it will be called when setting attributes on the class, but only after creating the class:
>>> class Meta(type):
... def __setattr__(cls, name, value):
... print "%s=%r" % (name, value)
...
>>> class A(object):
... __metaclass__ = Meta
...
>>> A.a = 1
a=1
But it won't work at the time of class definition, so it's probably not what you want.
Getting the class attributes in the metaclass __init__() works, but you loose the order of definition (and multiple definitions as well).
What I would do to solve your problem - but not your question - is to set the timestamp of the field creation create a counter of Field objects and set the current value of the counter to the created one:
class Field(object):
count = 0
def __init__(self, value, default=None, desc=None):
self.value = value
self.default = default
self.desc = desc
# Here comes the magic
self.nth = Field.count
Field.count += 1
# self.created_at = time.time()
Then I would create a method for returning all fields ordered by its counter value:
class CfgObj(object):
def params(self):
ns = dir(self)
fs = [getattr(self, field)
for field in ns
if isinstance(getattr(self, field), Field)]
# fs = sorted(fs, key=lambda f: f.created_at)
fs = sorted(fs, key=lambda f: f.nth)
return fs
Its usage is intuitive:
class ACfg(CfgObj):
setting1 = Field(str, default='set1', desc='setting1 ...')
setting2 = Field(int, default=5, desc='setting2...')
print ACfg().params()
Clearly the fields are ordered by time of object creation, not field creation, but it can be enough for you. Is it?
I have a model where I want to use a class method to set the default of for a property:
class Organisation(db.Model):
name=db.StringProperty()
code=db.StringProperty(default=generate_code())
#classmethod
def generate_code(cls):
import random
codeChars='ABCDEF0123456789'
while True: # Make sure code is unique
code=random.choice(codeChars)+random.choice(codeChars)+\
random.choice(codeChars)+random.choice(codeChars)
if not cls.all().filter('code = ',code).get(keys_only=True):
return code
But I get a NameError:
NameError: name 'generate_code' is not defined
How can I access generate_code()?
As I said in a comment, I would use a classmethod to act as a factory and always create you entity through there. It keeps things simpler and no nasty hooks to get the behaviour you want.
Here is a quick example.
class Organisation(db.Model):
name=db.StringProperty()
code=db.StringProperty()
#classmethod
def generate_code(cls):
import random
codeChars='ABCDEF0123456789'
while True: # Make sure code is unique
code=random.choice(codeChars)+random.choice(codeChars)+\
random.choice(codeChars)+random.choice(codeChars)
if not cls.all().filter('code = ',code).get(keys_only=True):
return code
#classmethod
def make_organisation(cls,*args,**kwargs):
new_org = cls(*args,**kwargs)
new_org.code = cls.generate_code()
return new_org
import random
class Test(object):
def __new__(cls):
cls.my_attr = cls.get_code()
return super(Test, cls).__new__(cls)
#classmethod
def get_code(cls):
return random.randrange(10)
t = Test()
print t.my_attr
You need specify the class name: Organisation.generate_code()