1

我正在尝试将我用 PHP 编写的东西移植到 Python 中,主要是为了更好地学习这门语言。有问题的代码是一个 SWF 解析器。在 PHP 中,我将所有数据结构都声明为类。我正在尝试在 Python 中做同样的事情,但似乎没有明确的方式来声明类变量。所以我最终得到了许多看起来像这样的类:

class SWFRGBA(object):
    red = 0
    green = 0
    blue = 0
    alpha = 0

Pythoners真的会写这样的东西吗?

[编辑]

让我发布一些实际代码来说明这个问题。下面的函数读取 SWF 文件中的矢量形状。readUB(), readSB() 读取一定数量的位,将它们解释为无符号或有符号。有时,给定字段所需的位数本身是从比特流中读取的。可能会出现三种类型的记录:直边、二次曲线或样式变化。样式更改记录可能会移动笔位置、更改线条样式索引、更改两个填充样式索引之一或替换样式数组。

protected function readShapeRecords($numFillBits, $numLineBits, $version, &$bytesAvailable) {
    $records = array();
    while($bytesAvailable) {
        if($this->readUB(1, $bytesAvailable)) {
            // edge
            if($this->readUB(1, $bytesAvailable)) {
                // straight
                $line = new SWFStraightEdge;
                $line->numBits = $this->readUB(4, $bytesAvailable) + 2;
                if($this->readUB(1, $bytesAvailable)) {
                    // general line
                    $line->deltaX = $this->readSB($line->numBits, $bytesAvailable);
                    $line->deltaY = $this->readSB($line->numBits, $bytesAvailable);
                } else {
                    if($this->readUB(1, $bytesAvailable)) {
                        // vertical
                        $line->deltaX = 0;
                        $line->deltaY = $this->readSB($line->numBits, $bytesAvailable);
                    } else {
                        // horizontal 
                        $line->deltaX = $this->readSB($line->numBits, $bytesAvailable);
                        $line->deltaY = 0;
                    }
                }
                $records[] = $line;
            } else {
                // curve
                $curve = new SWFQuadraticCurve;
                $curve->numBits = $this->readUB(4, $bytesAvailable) + 2;
                $curve->controlDeltaX = $this->readSB($curve->numBits, $bytesAvailable);
                $curve->controlDeltaY = $this->readSB($curve->numBits, $bytesAvailable);
                $curve->anchorDeltaX = $this->readSB($curve->numBits, $bytesAvailable);
                $curve->anchorDeltaY = $this->readSB($curve->numBits, $bytesAvailable);
                $records[] = $curve;
            }
        } else {
            $flags = $this->readUB(5, $bytesAvailable);
            if(!$flags) {
                break;
            } else {
                // style change
                $change = new SWFStyleChange;
                if($flags & 0x01) {
                    $change->numMoveBits = $this->readSB(5, $bytesAvailable);
                    $change->moveDeltaX = $this->readSB($change->numMoveBits, $bytesAvailable);
                    $change->moveDeltaY = $this->readSB($change->numMoveBits, $bytesAvailable);
                }
                if($flags & 0x02) {
                    $change->fillStyle0 = $this->readUB($numFillBits, $bytesAvailable);
                }
                if($flags & 0x04) {
                    $change->fillStyle1 = $this->readUB($numFillBits, $bytesAvailable);
                }
                if($flags & 0x08) {
                    $change->lineStyle = $this->readUB($numLineBits, $bytesAvailable);
                }
                if($flags & 0x10) {
                    $change->newFillStyles = $this->readFillStyles($version, $bytesAvailable);
                    $change->newLineStyles = $this->readLineStyles($version, $bytesAvailable);
                    $change->numFillBits = $numFillBits = $this->readUB(4, $bytesAvailable);
                    $change->numLineBits = $numLineBits = $this->readUB(4, $bytesAvailable);
                }
                $records[] = $change;
            }
        }
    }
    $this->alignToByte();
    return $records;
}
4

4 回答 4

8

如果你只想要拥有一堆属性的实例,你应该使用namedtuple

于 2012-08-11T20:48:08.793 回答
3

我不明白你说的意思:

但似乎没有明确的方式来声明一个类变量

您的代码片段定义了一个具有 4 个类变量的类。

是的,在某些情况下,Python 程序员会编写这样的类。但是,至少在我看来,这更像是一组相关数据,而不是一个会产生对象的类。

就大小写而言,传统上它是小写的变量,大写的常量(从技术上讲,Python 中没有常量,但这是另一个讨论)。例如:

attempts = 5
attempts_on_target = 2
MAX_ATTEMPTS = 10
于 2012-08-11T20:49:05.587 回答
2

是的,我担心这样的类对于任何熟悉 Python 的人来说都会显得有些愚蠢。

一个真正的Pythonista 可能会使用一个元类来参数化你想要的类的制作。元类只是一个实例是其他类的类。这是一个可以完成我认为您想要的许多事情的示例(来自您的问题和评论):

from copy import copy

class MetaStruct(type):
    def __init__(cls, name, bases, cls_dict):
        try:
            fields = cls_dict['fields']
        except KeyError:
            raise TypeError("No 'fields' attribute defined in class " + `name`)

        # field names may be separated by whitespace and/or commas
        fields = fields.replace(',', ' ').split()
        del cls_dict['fields']  # keep out of class instances

        if 'default_field_value' not in cls_dict:
            default_field_value = None  # default default field value
        else:
            default_field_value = cls_dict['default_field_value']
            del cls_dict['default_field_value']   # keep out of class instances

        super(MetaStruct, cls).__init__(name, bases, cls_dict)

        def __init__(self, **kwds):
            """ __init__() for class %s """ % name
            self.__dict__.update(zip(fields, [copy(default_field_value)
                                                  for _ in xrange(len(fields))]))
            self.__dict__.update(**kwds)

        def __setattr__(self, field, value):
            """ Prevents new field names from being added after creation. """
            if field in self.__dict__:
                self.__dict__[field] = value  # avoid recursion!
            else:
                raise AttributeError('Can not add field %r to instance of %r' %
                                     (field, name))
        # add defined methods to class instance
        setattr(cls, '__init__', __init__)
        setattr(cls, '__setattr__', __setattr__)

使用如图所示定义的元类,您可以使用它来声明不同的类,然后创建它们的一个或多个实例。在 Python 中,内存主要是为您管理的,因此new显然不需要像 PHP 这样的运算符。因此,没有指针,因此对类成员的访问通常通过点符号而不是->.

话虽如此,下面是一个声明类结构类、创建它的几个单独实例并访问它们的成员的示例:

# sample usage
class SWF_RGBA(object):
    __metaclass__ = MetaStruct
    fields = 'red, green, blue, alpha'
    default_field_value = 0  # otherwise would be None

c1 = SWF_RGBA()
print vars(c1)  # {'blue': 0, 'alpha': 0, 'green': 0, 'red': 0}
c2 = SWF_RGBA(red=1, blue=4)
print vars(c2)  # {'blue': 4, 'green': 0, 'alpha': 0, 'red': 1}

您可以使用关键字参数在构造函数调用中根据需要为类的多个或少量字段分配值,关键字参数可以按任何顺序给出。未分配的字段被赋予默认值None。字段可以是任何类型。

可以使用点表示法来引用所创建类实例的任何现有字段:

print c2.blue  # 4
c2.green = 3  # assign a new value to existing green attribute

但是创建实例后无法添加新字段:

c2.bogus = 42  # AttributeError: Can not add field 'bogus' to instance of 'SWF_RGBA'
于 2012-08-12T09:51:23.367 回答
1

在某些情况下,类变量是可取的,但我认为并非如此。您需要的大多数成员变量通常都是实例变量,通过在init方法中为它们分配一个值来声明。

于 2012-08-11T20:46:55.490 回答